/*
 * JQuery URL Parser plugin
 * Developed and maintanined by Mark Perkins, mark@allmarkedup.com
 * Source repository: https://github.com/allmarkedup/jQuery-URL-Parser
 * Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details.
 */

;
(function($, undefined) {

	var tag2attr = {
		a : 'href',
		img : 'src',
		form : 'action',
		base : 'href',
		script : 'src',
		iframe : 'src',
		link : 'href'
	},

	key = [ "source", "protocol", "authority", "userInfo", "user", "password",
			"host", "port", "relative", "path", "directory", "file", "query",
			"fragment" ], // keys available to query

	aliases = {
		"anchor" : "fragment"
	}, // aliases for backwards compatability

	parser = {
		strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, // less
																																						// intuitive,
																																						// more
																																						// accurate
																																						// to
																																						// the
																																						// specs
		loose : /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
	// more intuitive, fails on relative paths and deviates from specs
	},

	querystring_parser = /(?:^|&|;)([^&=;]*)=?([^&;]*)/g, // supports both
															// ampersand and
															// semicolon-delimted
															// query string
															// key/value pairs

	fragment_parser = /(?:^|&|;)([^&=;]*)=?([^&;]*)/g; // supports both
														// ampersand and
														// semicolon-delimted
														// fragment key/value
														// pairs

	function parseUri(url, strictMode) {
		var str = decodeURI(url), res = parser[strictMode || false ? "strict"
				: "loose"].exec(str), uri = {
			attr : {},
			param : {},
			seg : {}
		}, i = 14;

		while (i--) {
			uri.attr[key[i]] = res[i] || "";
		}

		// build query and fragment parameters

		uri.param['query'] = {};
		uri.param['fragment'] = {};

		uri.attr['query'].replace(querystring_parser, function($0, $1, $2) {
			if ($1) {
				uri.param['query'][$1] = $2;
			}
		});

		uri.attr['fragment'].replace(fragment_parser, function($0, $1, $2) {
			if ($1) {
				uri.param['fragment'][$1] = $2;
			}
		});

		// split path and fragement into segments

		uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g, '').split('/');

		uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g, '')
				.split('/');

		// compile a 'base' domain attribute

		uri.attr['base'] = uri.attr.host ? uri.attr.protocol + "://"
				+ uri.attr.host + (uri.attr.port ? ":" + uri.attr.port : '')
				: '';

		return uri;
	}
	;

	function getAttrName(elm) {
		var tn = elm.tagName;
		if (tn !== undefined)
			return tag2attr[tn.toLowerCase()];
		return tn;
	}

	$.fn.url = function(strictMode) {
		var url = '';

		if (this.length) {
			url = $(this).attr(getAttrName(this[0])) || '';
		}

		return $.url(url, strictMode);
	};

	$.url = function(url, strictMode) {
		if (arguments.length === 1 && url === true) {
			strictMode = true;
			url = undefined;
		}

		strictMode = strictMode || false;
		url = url || window.location.toString();

		return {

			data : parseUri(url, strictMode),

			// get various attributes from the URI
			attr : function(attr) {
				attr = aliases[attr] || attr;
				return attr !== undefined ? this.data.attr[attr]
						: this.data.attr;
			},

			// return query string parameters
			param : function(param) {
				return param !== undefined ? this.data.param.query[param]
						: this.data.param.query;
			},

			// return fragment parameters
			fparam : function(param) {
				return param !== undefined ? this.data.param.fragment[param]
						: this.data.param.fragment;
			},

			// return path segments
			segment : function(seg) {
				if (seg === undefined) {
					return this.data.seg.path;
				} else {
					seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative
																				// segments
																				// count
																				// from
																				// the
																				// end
					return this.data.seg.path[seg];
				}
			},

			// return fragment segments
			fsegment : function(seg) {
				if (seg === undefined) {
					return this.data.seg.fragment;
				} else {
					seg = seg < 0 ? this.data.seg.fragment.length + seg
							: seg - 1; // negative segments count from the end
					return this.data.seg.fragment[seg];
				}
			}

		};

	};

})(jQuery);